/**
 * Sep 12, 2013 8:59:56 AM
 * com.kratonsolution.belian.security.impl.service
 * UserServiceImpl.java
 */
package com.kratonsolution.belian.security.impl.service;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jasypt.util.password.StrongPasswordEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Strings;
import com.kratonsolution.belian.kernel.service.AccessPermision;
import com.kratonsolution.belian.kernel.service.AutoInjectPrimaryKey;
import com.kratonsolution.belian.kernel.service.EService;
import com.kratonsolution.belian.kernel.service.PagingSupport;
import com.kratonsolution.belian.kernel.service.Permission;
import com.kratonsolution.belian.security.api.dao.UserDao;
import com.kratonsolution.belian.security.api.dm.User;
import com.kratonsolution.belian.security.api.service.UserService;

/**
 * @author Agung Dodi Perdana
 * @email agung.dodi.perdana@gmail.com
 * @Version Sinch 0.0.1
 */
@Component
@Transactional(rollbackFor=Exception.class)
public class UserServiceImpl implements UserService
{
    private Logger log = Logger.getLogger(getClass());
    
    @Autowired
    private UserDao userDao;
    
    @Autowired
    private UserServiceRegistry registry;
    
    @Autowired
    private StrongPasswordEncryptor encryptor;
    
    @Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
    @AccessPermision(type=Permission.NONE,serviceCode=EService.USER)
    public boolean signin(String email, String password)
    {
        log.info("User trying to loged in -> "+email);
        
        if(Strings.isNullOrEmpty(email) || Strings.isNullOrEmpty(password))
            return false;
         
        User user = userDao.loadByEmail(email);
        if(user == null)
        {
            log.info("user doesnot exist........");
            return false;
        }
        
        boolean match = encryptor.checkPassword(password, user.getPassword());
        if(!match)
            log.info("Login failur for user using email -> "+email);
        
        user.setLastLogin(new Timestamp(System.currentTimeMillis()));
        user.setLogedIn(true);
        
        userDao.update(user);
        
        registry.init(email);
        
        return match;
    }

    @AccessPermision(type=Permission.ADD,serviceCode=EService.USER)
    @AutoInjectPrimaryKey
    public User store(String email,User model)
    {
        log.info("saving new user ---> "+model.getId());
        User user = userDao.store(model);
        log.info("Stored user ["+user+"]");
        return user;
    }

    @Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
    @AccessPermision(type=Permission.READ,serviceCode=EService.USER)
    public User load(String email,String id)
    {
        return userDao.load(id);
    }
    
    @Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
    @AccessPermision(type=Permission.READ,serviceCode=EService.USER)
    public User loadByEmail(String email,String loaded_email)
    {
        return userDao.loadByEmail(loaded_email);
    }

    @AccessPermision(type=Permission.UPDATE,serviceCode=EService.USER)
    public User update(String email,User model)
    {
        log.info("updating user.................");
        model.setLastUpdatedTime(new Timestamp(System.currentTimeMillis()));
        userDao.update(model);
        log.info("updated object ["+model+"]");
        
        return model;
    }

    @AccessPermision(type=Permission.DELETE,serviceCode=EService.USER)
    public User remove(String email,User model)
    {
        log.info("removing object ...............");
        userDao.remove(model);
        return model;
    }

    @Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
    @AccessPermision(type=Permission.READ,serviceCode=EService.USER)
    public List<User> loads(String email)
    {
        return userDao.loads();
    }

    @Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
    @AccessPermision(type=Permission.UPDATE,serviceCode=EService.USER)
    public boolean signout(String email)
    {
        User user = load(email,email);
        if(user != null)
        {
            user.setLogedIn(false);
            userDao.update(user);
        }
        
        return true;
    }

    @AccessPermision(type=Permission.UPDATE,serviceCode=EService.USER)
    public boolean changePassword(String email,String oldPassword, String newPassword1, String newPassword2)
    {
        if(newPassword1.equals(newPassword2))
        {
            User user = load(email,email);
            if(user != null)
            {
                if(encryptor.checkPassword(oldPassword, user.getPassword()))
                {
                    user.setPassword(newPassword2);
                    userDao.update(user);
                }
            }
        }
        
        return true;
    }

    @PagingSupport(dao=UserDao.class)
    @AccessPermision(type=Permission.READ,serviceCode=EService.USER)
    public Map<String, Object> loads(String email,Map<String, Object> param)
    {
        Map<String,Object> map = new HashMap<String, Object>();
        map.put("users",userDao.loads(param));
        
        return map;
    }
}
